/**
 * 
 */
package com.ge.healthcare.autosc.onwatch.service;

import java.util.HashMap;
import java.util.Map;

import com.ge.healthcare.autosc.common.ASCLogger;
import com.ge.healthcare.autosc.common.ASCUtil;
import com.ge.healthcare.autosc.common.commands.FTPCommand;
import com.ge.healthcare.autosc.common.commands.IFTCommand;
import com.ge.healthcare.autosc.common.commands.SFTPCommand;
import com.ge.healthcare.autosc.common.database.dao.IModelTypePropDAO;
import com.ge.healthcare.autosc.common.database.dao.ISystemDetailsDAO;
import com.ge.healthcare.autosc.common.exceptions.FTPCommandException;
import com.ge.healthcare.autosc.common.exceptions.GSCCUtilException;
import com.ge.healthcare.autosc.common.exceptions.InvalidLoginCredentialsException;
import com.ge.healthcare.autosc.common.exceptions.SFTPCommandException;
import com.ge.healthcare.autosc.common.pojo.sysInfo.SystemDetails;
import com.ge.healthcare.autosc.common.pojo.sysInfo.SystemInfo;
import com.ge.healthcare.autosc.common.util.ApplicationInfo;
import com.ge.healthcare.autosc.common.util.ConnectivityUtil;
import com.ge.healthcare.autosc.common.util.GSCCUtil;
import com.ge.healthcare.autosc.common.util.PropertyConstants;
import com.ge.healthcare.autosc.onwatch.exception.OnWatchException;
import com.ge.healthcare.autosc.onwatch.util.OnWatchCodeConstants;
import com.ge.med.service.mc.exceptions.MakeConnectionException;

/**
 * @author 212042764
 * 
 */
public class IIPHttpClientPkgDownloader {
	/** Onwatch failed to establish make connection */
	public static final String PRC_ONW_F_MCF_001 = "PRC_ONW_F_MCF_001";

	private static IModelTypePropDAO modelTypePropDAO = null;
	private static ISystemDetailsDAO systemDetailsDAO = null;
	private String systemId = null;
	private SystemInfo systemInfo = null;
	private boolean ftpAllowed = false;
	private String defaultUser = null;
	private String defaultPasswd = null;
	private String localFile = null;
	private String remoteFile = null;
	private IFTCommand command = null;
	private boolean success = false;
	private boolean continueTransfer = false;

	/**
	 * Constrcutor called by Spring
	 */
	public IIPHttpClientPkgDownloader() {
		super();
	}

	/**
	 * Constructor called from servlet filter
	 * 
	 * @param systemId
	 */
	public IIPHttpClientPkgDownloader(String systemId) {
		this.systemId = systemId;
	}

	/**
	 * Transfer the newer version of IIPHttpClient to the device
	 * 
	 * @throws OnWatchException
	 */
	public void execute() throws OnWatchException {
		ASCLogger.info(this.getClass(), "execute",
				"IIPHttpClientPkgDownloader invoked");
		this.init();
		if (continueTransfer) {
			try {
				this.makeConnection();
				this.transferPackage();
				success = true;
			} finally {
				this.addChronology();
				this.cleanup();
			}
			ASCLogger.info(this.getClass(), "execute",
					"IIPHttpClientPkgDownloader completed");
		} else {
			ASCLogger.info(this.getClass(), "execute",
					"IIPHttpClientPkgDownloader action is not allowed for system:"
							+ systemInfo);
		}
	}

	/**
	 * Initializes requires variables
	 * 
	 * @throws OnWatchException
	 */
	private void init() throws OnWatchException {
		if (ASCUtil.isNullOrEmpty(systemId)) {
			throw new OnWatchException("System Id is null");
		}
		systemInfo = getSystemInfo(systemId);
		this.initLoginDetails();
		this.checkIfTransferAllowed();
		this.initTransferLocation();
	}

	/**
	 * List of systems to which transfer is allowed
	 */
	private void checkIfTransferAllowed() {
		String methodName = "checkIfTransferAllowed";
		continueTransfer = new Boolean(modelTypePropDAO.getValueForProperty(
				systemInfo.getModality(), systemInfo.getProductLine(),
				systemInfo.getModelType(),
				IModelTypePropDAO.IIPHTTPCLIENT_TRANSFER_ALLOWED));
		if (continueTransfer
				&& new Boolean(modelTypePropDAO.getValueForProperty(
						systemInfo.getModality(), systemInfo.getProductLine(),
						systemInfo.getModelType(),
						IModelTypePropDAO.IIPHTTPCLIENT_TRANSFER_PERSYS))) {
			if (ASCUtil.isNullOrEmptyObject(systemDetailsDAO
					.getSystemDetails(systemId))) {
				continueTransfer = false;
				ASCLogger.info(this.getClass(), methodName, String.format(
						"System Id: %s is not present in effectivity list",
						systemId));
			} else {
				ASCLogger.info(this.getClass(), methodName, String.format(
						"System Id: %s is present in effectivity list",
						systemId));
			}
		}
	}

	/**
	 * Brings remote device to 3. domain
	 * 
	 * @throws OnWatchException
	 */
	private void makeConnection() throws OnWatchException {
		try {
			ConnectivityUtil.makeConnection(systemId,
					this.getClass().getName(), 1, null);
		} catch (MakeConnectionException mcException) {
			String message = "Make Connection call failed for systemId:"
					+ systemId;
			throw new OnWatchException(message, mcException, PRC_ONW_F_MCF_001);
		}
	}

	/**
	 * Initializes Login Details
	 */
	private void initLoginDetails() {
		String methodName = "initLoginDetails";
		defaultUser = ApplicationInfo.getInstance().getProperty(
				PropertyConstants.ONWATCH_IIPENGINE_TRANSFER_DEFAULT_USER,
				"insite");
		defaultPasswd = systemInfo.getLoginInfo().getProperty(defaultUser);
		ASCLogger.info(this.getClass(), methodName, "defaultUser:"
				+ defaultUser);
	}

	/**
	 * Identifies the location of input and remote destination
	 */
	private void initTransferLocation() {
		String methodName = "initTransferLocation";
		if (continueTransfer) {
			localFile = modelTypePropDAO.getValueForProperty(
					systemInfo.getModality(), systemInfo.getProductLine(),
					systemInfo.getModelType(),
					IModelTypePropDAO.IIPHTTPCLIENT_PKG_LOC_BO);
			remoteFile = modelTypePropDAO.getValueForProperty(
					systemInfo.getModality(), systemInfo.getProductLine(),
					systemInfo.getModelType(),
					IModelTypePropDAO.IIPHTTPCLIENT_PKG_LOC_IIP);
			ftpAllowed = new Boolean(modelTypePropDAO.getValueForProperty(
					systemInfo.getModality(), systemInfo.getProductLine(),
					systemInfo.getModelType(),
					IModelTypePropDAO.IIPHTTPCLIENT_USE_FTP));
		}
		ASCLogger.info(this.getClass(), methodName, String.format(
				"localFile:%s remoteFile:%s ftpAllowed:%s continueTransfer:%s",
				localFile, remoteFile, ftpAllowed, continueTransfer));
	}

	/**
	 * Retrieves system info
	 * 
	 * @param systemId
	 * @return
	 * @throws OnWatchException
	 */
	private SystemInfo getSystemInfo(String systemId) throws OnWatchException {
		SystemDetails systemDetails = null;
		SystemInfo systemInfo = null;
		try {
			systemDetails = GSCCUtil.getSystemDetailsForSystemId(systemId);
			if (systemDetails == null) {
				StringBuffer errorStr = new StringBuffer().append(
						"Cannot find system for systemId ").append(systemId);
				throw new OnWatchException(errorStr.toString(),
						OnWatchCodeConstants.PRC_F_OWR_001);
			}
			systemInfo = new SystemInfo(systemDetails);
		} catch (GSCCUtilException gue) {
			String msg = "Error retrieving system information for system "
					+ systemId;
			throw new OnWatchException(msg, gue,
					OnWatchCodeConstants.PRC_F_OWR_002);
		}
		return systemInfo;
	}

	/**
	 * Transfers package to remote device
	 * 
	 * @throws OnWatchException
	 */
	private void transferPackage() throws OnWatchException {
		String methodName = "transferPackage";
		try {
			IFTCommand command = this.getCommand();
			ASCLogger.info(this.getClass(), methodName, "Command:" + command);
			command.login(systemInfo.getIpAddress(), defaultUser, defaultPasswd);
			ASCLogger.info(this.getClass(), methodName, "Login successful as: "
					+ defaultUser);
			command.putFile(localFile, remoteFile + ".tmp");
			command.mv(remoteFile, remoteFile + ".old");
			command.mv(remoteFile + ".tmp", remoteFile);
			command.chmod(IFTCommand.ALL_PERMISSIONS,
					IFTCommand.READ_EXECUTE_PERMISSIONS,
					IFTCommand.READ_EXECUTE_PERMISSIONS, remoteFile);
			ASCLogger.info(this.getClass(), methodName, String.format(
					"LocalFile: %s successfully transferred to: %s", localFile,
					remoteFile));
		} catch (FTPCommandException ftpException) {
			throw new OnWatchException(ftpException,
					OnWatchCodeConstants.PRC_F_OWR_039);
		} catch (SFTPCommandException sftpException) {
			throw new OnWatchException(sftpException,
					OnWatchCodeConstants.PRC_F_OWR_038);
		} catch (InvalidLoginCredentialsException loginExcep) {
			throw new OnWatchException(loginExcep,
					OnWatchCodeConstants.PRC_F_OWR_037);
		}
	}

	/**
	 * Retrieves command using ftp and sftp
	 * 
	 * @return
	 * @throws SFTPCommandException
	 */
	private IFTCommand getCommand() throws SFTPCommandException {
		IFTCommand command = null;
		if (ftpAllowed) {
			command = new FTPCommand();
		} else {
			command = new SFTPCommand();
		}
		return command;
	}

	/**
	 * Adds chronology entry. This is need for customer connectivity information
	 */
	protected void addChronology() {
		Map<String, String> chronologyMap = new HashMap<String, String>();
		chronologyMap.put(GSCCUtil.APPLICATION, "AutoSC");
		chronologyMap.put(GSCCUtil.ATTEMPT_NUM, 1 + "");
		String completionCode = "Failure";
		if (success) {
			completionCode = "Success";
		}
		chronologyMap.put(GSCCUtil.COMPLETION_CODE, completionCode);
		chronologyMap.put(GSCCUtil.COMMENT, "IIPHttpClientUpdator "
				+ completionCode);
		chronologyMap.put(GSCCUtil.LOGIN_ID, "asc_acct");
		chronologyMap.put(GSCCUtil.PLATFORM, "IIPHttpClientUpdator");
		chronologyMap.put(GSCCUtil.SYSTEM_ID, systemId);
		chronologyMap.put(GSCCUtil.TYPE_ID, "Outbound");
		GSCCUtil.addChronology(chronologyMap);
	}

	/**
	 * Performs cleanup after task execution
	 */
	private void cleanup() {
		if (!ASCUtil.isNullOrEmptyObject(command)) {
			try {
				command.logout();
			} catch (FTPCommandException ftpExcep) {
				ASCLogger.info(this.getClass(), "cleanup",
						"Failed to close FTP Connection");
			} catch (SFTPCommandException sftpExcep) {
				ASCLogger.info(this.getClass(), "cleanup",
						"Failed to close SFTP Connection");
			}
		}
	}

	/**
	 * @return the modelTypePropDAO
	 */
	public IModelTypePropDAO getModelTypePropDAO() {
		return modelTypePropDAO;
	}

	/**
	 * @param modelTypePropDAO
	 *            the modelTypePropDAO to set
	 */
	public void setModelTypePropDAO(IModelTypePropDAO modelTypePropDAO) {
		IIPHttpClientPkgDownloader.modelTypePropDAO = modelTypePropDAO;
	}

	/**
	 * @return the systemDetailsDAO
	 */
	public ISystemDetailsDAO getSystemDetailsDAO() {
		return systemDetailsDAO;
	}

	/**
	 * @param systemDetailsDAO the systemDetailsDAO to set
	 */
	public void setSystemDetailsDAO(ISystemDetailsDAO systemDetailsDAO) {
		IIPHttpClientPkgDownloader.systemDetailsDAO = systemDetailsDAO;
	}
}
